﻿

namespace Test
 module Dynamic = 

    open System
    open System.Windows
    open System.Windows.Media
    open System.Windows.Shapes
    open System.Windows.Controls
    open System.Windows.Threading
    open FsSignals.Signal
      
    module Wheel = 
        type Model = 
            {
                velocityS : Slider
                velocityTB : TextBox

                angleTB : TextBox

                resetB : Button
            }
        
        let resetModel model = 
            model.velocityS.Value <- 0.0
            model.velocityS.Maximum <- 100.0
            model.velocityS.Minimum <- (-100.0)
            model.velocityS.Width <- (100.0)

            model.velocityTB.Text <- "0"
            model.angleTB.Text <- "0"
            model.resetB.Content <- "Start Again"
            model

        let initPanel () = 
            let model =
              {
                velocityS = new Slider()
                velocityTB = new TextBox()
                angleTB = new TextBox()
                resetB = new Button()
              }
            
            resetModel model

            let sp1 = new StackPanel()
            sp1.Margin <- new Thickness(10.0)
            let sp = new StackPanel()
            sp.Orientation <- Orientation.Horizontal 
            sp.HorizontalAlignment <- HorizontalAlignment.Left
            sp.Children.Add(model.velocityS)
            sp.Children.Add(model.velocityTB)
            sp.Children.Add(model.angleTB)
            sp.Children.Add(model.resetB)

            sp1.Children.Add(sp)

            (sp1, model)


        let makeWheelPanel () =
            let (panel, model) = initPanel ()
            let timer = new DispatcherTimer()
            let interval = 1.0
            timer.Interval <- TimeSpan.FromSeconds(interval)
            timer.Start()

            let rec engine() =
                resetModel model
                
                
                let timeSig = sourceEvent timer.Tick ==>> (fun _ x  -> x+interval) |> stepAccumSig 0.0
                let velocitySig = sourceEvent model.velocityS.ValueChanged =>> fun v -> v.NewValue
                let s1 = integrateSig 0.0 0.0 velocitySig timeSig
                let s2 = map (fun x -> model.angleTB.Text <- (sprintf "%A" x)) s1
                let s3 =  map (fun x -> model.velocityTB.Text <- (sprintf "%A" x)) velocitySig
                let resetSig = sourceEvent  model.resetB.Click ==>>  fun _ -> dispose s3 // avoid space leaks
                                                                              engine ()
 
                switch s2 resetSig
            engine()

            panel

            
        // integrate speed up to a min or max position (angle)
        let makeBoundedWheelPanel () =
            let (panel, model) = initPanel ()
            let timer = new DispatcherTimer()
            let interval = 1.0
            timer.Interval <- TimeSpan.FromSeconds(interval)
            timer.Start()

            let rec engine() =
                resetModel model
                let min = -500.0
                let max = +500.0
                let rec integrate i0 t0 velocitySig timeSig =    
                    let s1 = integrateSig i0 t0 velocitySig timeSig =>> fun v-> 
                        if v >= max then max else v
                    let overflowSig = s1 |> filter (fun v ->    printfn "%A" v
                                                                v >= max) 
                    let blockedOnMax = sample (two s1 timeSig) overflowSig =>> (fun (i0, t0) -> printfn "blocked"
                                                                                                integrate max t0 velocitySig timeSig)
                    let s2 = switch s1 blockedOnMax
                    s2

                let timeSig = sourceEvent timer.Tick ==>> (fun _ x  -> x+interval) |> stepAccumSig 0.0
                let velocitySig = sourceEvent model.velocityS.ValueChanged =>> fun v -> v.NewValue
                let s1 = integrate 0.0 0.0 velocitySig timeSig
                let s2 = map (fun x -> model.angleTB.Text <- (sprintf "%A" x)) s1
                let s3 =  map (fun x -> model.velocityTB.Text <- (sprintf "%A" x)) velocitySig
                let resetSig = sourceEvent  model.resetB.Click ==>>  fun _ -> dispose s3 // avoid space leaks
                                                                              engine ()
 
                switch s2 resetSig
            engine()

            panel
